package com.smart.community.commons.utils;

import lombok.extern.slf4j.Slf4j;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * 日期时间工具类
 * @author Wu.Liang
 * @since 2024-12-19
 * @version 1.0.0
 */
@Slf4j
public class DateUtils {
    
    /**
     * 默认日期时间格式
     */
    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    
    /**
     * 默认日期格式
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    
    /**
     * 默认时间格式
     */
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    
    /**
     * 年月格式
     */
    public static final String YEAR_MONTH_FORMAT = "yyyy-MM";
    
    /**
     * 年月日时分格式
     */
    public static final String DATETIME_MINUTE_FORMAT = "yyyy-MM-dd HH:mm";
    
    /**
     * 时间戳格式
     */
    public static final String TIMESTAMP_FORMAT = "yyyyMMddHHmmss";
    
    /**
     * 默认日期时间格式化器
     */
    public static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT);
    
    /**
     * 默认日期格式化器
     */
    public static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT);
    
    /**
     * 默认时间格式化器
     */
    public static final DateTimeFormatter DEFAULT_TIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT);
    
    /**
     * 年月格式化器
     */
    public static final DateTimeFormatter YEAR_MONTH_FORMATTER = DateTimeFormatter.ofPattern(YEAR_MONTH_FORMAT);
    
    /**
     * 年月日时分格式化器
     */
    public static final DateTimeFormatter DATETIME_MINUTE_FORMATTER = DateTimeFormatter.ofPattern(DATETIME_MINUTE_FORMAT);
    
    /**
     * 时间戳格式化器
     */
    public static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(TIMESTAMP_FORMAT);
    
    /**
     * 获取当前日期时间
     * 
     * @return 当前日期时间
     */
    public static LocalDateTime now() {
        return LocalDateTime.now();
    }
    
    /**
     * 获取当前日期
     * 
     * @return 当前日期
     */
    public static LocalDate today() {
        return LocalDate.now();
    }
    
    /**
     * 获取当前时间
     * 
     * @return 当前时间
     */
    public static LocalTime currentTime() {
        return LocalTime.now();
    }
    
    /**
     * 获取当前时间戳
     * 
     * @return 当前时间戳
     */
    public static long currentTimestamp() {
        return System.currentTimeMillis();
    }
    
    /**
     * 格式化日期时间
     * 
     * @param dateTime 日期时间
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime) {
        return format(dateTime, DEFAULT_DATETIME_FORMAT);
    }
    
    /**
     * 格式化日期时间
     * 
     * @param dateTime 日期时间
     * @param pattern 格式
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime, String pattern) {
        if (dateTime == null) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return dateTime.format(formatter);
        } catch (Exception e) {
            log.error("格式化日期时间失败: dateTime={}, pattern={}", dateTime, pattern, e);
            return null;
        }
    }
    
    /**
     * 格式化日期
     * 
     * @param date 日期
     * @return 格式化后的字符串
     */
    public static String format(LocalDate date) {
        return format(date, DEFAULT_DATE_FORMAT);
    }
    
    /**
     * 格式化日期
     * 
     * @param date 日期
     * @param pattern 格式
     * @return 格式化后的字符串
     */
    public static String format(LocalDate date, String pattern) {
        if (date == null) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return date.format(formatter);
        } catch (Exception e) {
            log.error("格式化日期失败: date={}, pattern={}", date, pattern, e);
            return null;
        }
    }
    
    /**
     * 格式化时间
     * 
     * @param time 时间
     * @return 格式化后的字符串
     */
    public static String format(LocalTime time) {
        return format(time, DEFAULT_TIME_FORMAT);
    }
    
    /**
     * 格式化时间
     * 
     * @param time 时间
     * @param pattern 格式
     * @return 格式化后的字符串
     */
    public static String format(LocalTime time, String pattern) {
        if (time == null) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return time.format(formatter);
        } catch (Exception e) {
            log.error("格式化时间失败: time={}, pattern={}", time, pattern, e);
            return null;
        }
    }
    
    /**
     * 解析日期时间字符串
     * 
     * @param dateTimeStr 日期时间字符串
     * @return 日期时间
     */
    public static LocalDateTime parseDateTime(String dateTimeStr) {
        return parseDateTime(dateTimeStr, DEFAULT_DATETIME_FORMAT);
    }
    
    /**
     * 解析日期时间字符串
     * 
     * @param dateTimeStr 日期时间字符串
     * @param pattern 格式
     * @return 日期时间
     */
    public static LocalDateTime parseDateTime(String dateTimeStr, String pattern) {
        if (StringUtils.isEmpty(dateTimeStr)) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return LocalDateTime.parse(dateTimeStr, formatter);
        } catch (Exception e) {
            log.error("解析日期时间失败: dateTimeStr={}, pattern={}", dateTimeStr, pattern, e);
            return null;
        }
    }
    
    /**
     * 解析日期字符串
     * 
     * @param dateStr 日期字符串
     * @return 日期
     */
    public static LocalDate parseDate(String dateStr) {
        return parseDate(dateStr, DEFAULT_DATE_FORMAT);
    }
    
    /**
     * 解析日期字符串
     * 
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return 日期
     */
    public static LocalDate parseDate(String dateStr, String pattern) {
        if (StringUtils.isEmpty(dateStr)) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return LocalDate.parse(dateStr, formatter);
        } catch (Exception e) {
            log.error("解析日期失败: dateStr={}, pattern={}", dateStr, pattern, e);
            return null;
        }
    }
    
    /**
     * 解析时间字符串
     * 
     * @param timeStr 时间字符串
     * @return 时间
     */
    public static LocalTime parseTime(String timeStr) {
        return parseTime(timeStr, DEFAULT_TIME_FORMAT);
    }
    
    /**
     * 解析时间字符串
     * 
     * @param timeStr 时间字符串
     * @param pattern 格式
     * @return 时间
     */
    public static LocalTime parseTime(String timeStr, String pattern) {
        if (StringUtils.isEmpty(timeStr)) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return LocalTime.parse(timeStr, formatter);
        } catch (Exception e) {
            log.error("解析时间失败: timeStr={}, pattern={}", timeStr, pattern, e);
            return null;
        }
    }
    
    /**
     * Date转LocalDate
     * 
     * @param date Date
     * @return LocalDate
     */
    public static LocalDate toLocalDate(Date date) {
    	if (date == null) {
    		return null;
    	}
    	return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }
    
    /**
     * Date转LocalDateTime
     * 
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }
    
    /**
     * LocalDateTime转Date
     * 
     * @param dateTime LocalDateTime
     * @return Date
     */
    public static Date toDate(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    /**
     * LocalDate转Date
     * 
     * @param date LocalDate
     * @return Date
     */
    public static Date toDate(LocalDate date) {
        if (date == null) {
            return null;
        }
        return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }
    
    /**
     * 获取两个日期时间之间的天数
     * 
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 天数
     */
    public static long daysBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.DAYS.between(startDateTime, endDateTime);
    }
    
    /**
     * 获取两个日期之间的天数
     * 
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 天数
     */
    public static long daysBetween(LocalDate startDate, LocalDate endDate) {
        if (startDate == null || endDate == null) {
            return 0;
        }
        return ChronoUnit.DAYS.between(startDate, endDate);
    }
    
    /**
     * 获取两个日期时间之间的小时数
     * 
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 小时数
     */
    public static long hoursBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.HOURS.between(startDateTime, endDateTime);
    }
    
    /**
     * 获取两个日期时间之间的分钟数
     * 
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 分钟数
     */
    public static long minutesBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.MINUTES.between(startDateTime, endDateTime);
    }
    
    /**
     * 获取两个日期时间之间的秒数
     * 
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 秒数
     */
    public static long secondsBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        if (startDateTime == null || endDateTime == null) {
            return 0;
        }
        return ChronoUnit.SECONDS.between(startDateTime, endDateTime);
    }
    
    /**
     * 获取月份第一天
     * 
     * @param date 日期
     * @return 月份第一天
     */
    public static LocalDate firstDayOfMonth(LocalDate date) {
        if (date == null) {
            return null;
        }
        return date.with(TemporalAdjusters.firstDayOfMonth());
    }
    
    /**
     * 获取月份最后一天
     * 
     * @param date 日期
     * @return 月份最后一天
     */
    public static LocalDate lastDayOfMonth(LocalDate date) {
        if (date == null) {
            return null;
        }
        return date.with(TemporalAdjusters.lastDayOfMonth());
    }
    
    /**
     * 获取年份第一天
     * 
     * @param date 日期
     * @return 年份第一天
     */
    public static LocalDate firstDayOfYear(LocalDate date) {
        if (date == null) {
            return null;
        }
        return date.with(TemporalAdjusters.firstDayOfYear());
    }
    
    /**
     * 获取年份最后一天
     * 
     * @param date 日期
     * @return 年份最后一天
     */
    public static LocalDate lastDayOfYear(LocalDate date) {
        if (date == null) {
            return null;
        }
        return date.with(TemporalAdjusters.lastDayOfYear());
    }
    
    /**
     * 获取周第一天
     * 
     * @param date 日期
     * @return 周第一天
     */
    public static LocalDate firstDayOfWeek(LocalDate date) {
        if (date == null) {
            return null;
        }
        return date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }
    
    /**
     * 获取周最后一天
     * 
     * @param date 日期
     * @return 周最后一天
     */
    public static LocalDate lastDayOfWeek(LocalDate date) {
        if (date == null) {
            return null;
        }
        return date.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
    }
    
    /**
     * 判断是否为同一天
     * 
     * @param dateTime1 日期时间1
     * @param dateTime2 日期时间2
     * @return 是否为同一天
     */
    public static boolean isSameDay(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        if (dateTime1 == null || dateTime2 == null) {
            return false;
        }
        return dateTime1.toLocalDate().equals(dateTime2.toLocalDate());
    }
    
    /**
     * 判断是否为今天
     * 
     * @param dateTime 日期时间
     * @return 是否为今天
     */
    public static boolean isToday(LocalDateTime dateTime) {
        if (dateTime == null) {
            return false;
        }
        return dateTime.toLocalDate().equals(today());
    }
    
    /**
     * 判断是否为昨天
     * 
     * @param dateTime 日期时间
     * @return 是否为昨天
     */
    public static boolean isYesterday(LocalDateTime dateTime) {
        if (dateTime == null) {
            return false;
        }
        return dateTime.toLocalDate().equals(today().minusDays(1));
    }
    
    /**
     * 判断是否为明天
     * 
     * @param dateTime 日期时间
     * @return 是否为明天
     */
    public static boolean isTomorrow(LocalDateTime dateTime) {
        if (dateTime == null) {
            return false;
        }
        return dateTime.toLocalDate().equals(today().plusDays(1));
    }
}
